package com.database.daos.imp;

import java.util.*;

import org.hibernate.Hibernate;
import org.springframework.transaction.annotation.*;
import org.tmatesoft.svn.core.io.*;

import com.database.daos.IElementDao;
import com.database.objects.*;
import com.database.objects.Class;

public class ElementDao extends GenericDao<Element<?, ?>> implements IElementDao {

	private static final long serialVersionUID = 7142916326929217956L;

	@Override
	@SuppressWarnings("unchecked")
	@Transactional(propagation = Propagation.REQUIRED)
	public Commit getCommitByNumber(Project project, long number) {
		List<Commit> commits = findByNamedQueryAndNamedParam("Commit.getCommitByNumber", new String[] { "project", "number" }, new Object[] { project, number });
		Commit commit = !commits.isEmpty() ? commits.get(0) : null;
		initialize(commit);
		return commit;
	}

	@Transactional(propagation = Propagation.REQUIRED)
	private void initialize(Commit commit) {
		if (commit != null) {
			Hibernate.initialize(commit.getChilds());
			for (File file : commit.getChilds()) {
				initialize(file);
			}
		}
	}

	@Override
	@SuppressWarnings("unchecked")
	@Transactional(propagation = Propagation.REQUIRED)
	public File getPreviousFile(SVNRepository svnRepository, File file) {
		List<File> files = findByNamedQueryAndNamedParam("File.getPreviousFile", new String[] { "path", "number" }, new Object[] { file.getPath(), file.getParent().getNumber() });
		File previousFile = null;
		if (files.size() >= 2) {
			previousFile = files.get(1);
		} else if (!file.isDeleteStatus()) {
			try {
				long startRevision = 0;
				long endRevision = file.getParent().getNumber();
				Collection<?> previousCollection = svnRepository.getFileRevisions(file.getPath(), null, startRevision, endRevision);
				if (previousCollection.size() >= 2) {
					List<?> previousList = new ArrayList(previousCollection);
					SVNFileRevision fileRevision = (SVNFileRevision) previousList.get(previousList.size() - 2);
					String pathPrevious = fileRevision.getPath();
					files = findByNamedQueryAndNamedParam("File.getPreviousFile", new String[] { "path", "number" }, new Object[] { pathPrevious, endRevision });
					previousFile = !files.isEmpty() ? files.get(0) : null;
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		initialize(previousFile);
		return previousFile;
	}

	private void initialize(File file) {
		if (file != null) {
			if (file.isFileOO()) {
				FileOO fileOO = (FileOO) file;
				Hibernate.initialize(fileOO.getChilds());
				for (Element<?, ?> child : fileOO.getChilds()) {
					initialize((Class) child);
				}
			} else {
				FileNoOO fileNoOO = (FileNoOO) file;
				Hibernate.initialize(fileNoOO.getChilds());
			}
		}
	}

	@Override
	@SuppressWarnings("unchecked")
	@Transactional(propagation = Propagation.REQUIRED)
	public Class getPreviousClass(Class clazz) {
		FileOO file = clazz.getParent();
		List<Class> classes = findByNamedQueryAndNamedParam("Class.getPreviousClass", new String[] { "name", "path", "number" }, new Object[] { clazz.getName(), file.getPath(), file.getParent().getNumber() });
		Class previousClass = !classes.isEmpty() ? classes.get(0) : null;
		initialize(previousClass);
		return previousClass;
	}

	private void initialize(Class clazz) {
		if (clazz != null) {
			initialize(clazz.getFields());
			Hibernate.initialize(clazz.getChilds());
			for (Method method : clazz.getChilds()) {
				initialize(method);
			}
		}
	}

	@Override
	@SuppressWarnings("unchecked")
	@Transactional(propagation = Propagation.REQUIRED)
	public Method getPreviousMethod(Method method) {
		Class clazz = method.getParent();
		List<Method> methods = findByNamedQueryAndNamedParam("Method.getPreviousMethod", new String[] { "signature", "name", "number" }, new Object[] { method.getSignature(), clazz.getName(), clazz.getParent().getParent().getNumber() });
		Method previousMethod = !methods.isEmpty() ? methods.get(0) : null;
		initialize(previousMethod);
		return previousMethod;
	}

	private void initialize(Method method) {
		if (method != null) {
			Hibernate.initialize(method.getVariables());
			Hibernate.initialize(method.getChilds());
		}
	}

	@Override
	@SuppressWarnings("unchecked")
	public Issue getIssueByNumber(Project project, Long number) {
		List<Issue> issues = findByNamedQueryAndNamedParam("Issue.getIssueByNumber", new String[] { "project", "number" }, new Object[] { project, number });
		Issue issue = !issues.isEmpty() ? issues.get(0) : null;
		return issue;
	}

	@Override
	@SuppressWarnings("unchecked")
	public List<Element<?, ?>> findCommitsByDeveloper(Developer developer) {
		return findByNamedQueryAndNamedParam("Element.findCommitsByDeveloper", "developer", developer);
	}

	@Override
	@SuppressWarnings("unchecked")
	public List<Element<?, ?>> findIssuesByDeveloper(Developer developer) {
		return findByNamedQueryAndNamedParam("Element.findIssuesByDeveloper", "developer", developer);
	}

	@Override
	@SuppressWarnings("unchecked")
	@Transactional(propagation = Propagation.REQUIRED)
	public List<Class> findClassesByDeveloper(Developer developer) {
		List<Class> classes = findByNamedQueryAndNamedParam("Element.findClassesByDeveloper", "developer", developer);
		for (Class clazz : classes) {
			initialize(clazz);
		}
		return classes;
	}

}